import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Random;

import org.ejml.ops.MatrixIO;
import org.ejml.simple.SimpleMatrix;

public class Grafo {

	public static HashMap<Integer, Integer> dicionario1to2 = new HashMap<Integer, Integer>();
	public static HashMap<Integer, Integer> dicionario2to1 = new HashMap<Integer, Integer>();

	static int size;
	static SimpleMatrix matrizNos;
	static SimpleMatrix matrizClasses;

	static ArrayList<Integer> classesApagadas;

	// Mostra quanto o metodo acertou
	public static void compararResultados() throws IOException {

		double erro = 0;
		double numApagados = classesApagadas.size();

		BufferedReader br1 = new BufferedReader(new FileReader(
				"Resultados\\matriz_Classes_1.txt"));
		BufferedReader br2 = new BufferedReader(new FileReader(
				"Resultados\\matriz_Classes_2.txt"));
		BufferedReader br3 = new BufferedReader(new FileReader(
				"Resultados\\matriz_Classes_3.txt"));

		String sCurrentLine;
		while ((sCurrentLine = br1.readLine()) != null) {

			String classeApagada = br2.readLine();
			String classeClassificada = br3.readLine();

			if (!classeApagada.equals(sCurrentLine)
					&& !classeClassificada.equals(sCurrentLine)) {

				erro++;

			}

		}

		br1.close();
		br2.close();
		br3.close();

		System.out.println("\nErros: " + erro);
		System.out.println("%: " + ((erro / numApagados) * 100) + "%");

	}

	public static void criarMatrix_1() throws IOException {

		System.out.println("\nMatriz " + size + " x " + size);

		matrizNos = new SimpleMatrix(size, size);

		BufferedReader br = new BufferedReader(new FileReader("cora.cites"));

		String sCurrentLine;
		while ((sCurrentLine = br.readLine()) != null) {

			String[] cities = sCurrentLine.split("\t");

			int no1 = dicionario2to1.get(Integer.parseInt(cities[0]));
			int no2 = dicionario2to1.get(Integer.parseInt(cities[1]));

			matrizNos.set(no1, no2, 1);
			matrizNos.set(no2, no1, 1);

		}

		br.close();

		// MatrixIO.print(new PrintStream(new FileOutputStream(
		// "Resultados\\matriz_Classes_1.txt")), matrizNos.getMatrix());

		// matriz.print();

	}

	public static void criarMatriz_2() throws IOException {

		BufferedReader br = new BufferedReader(new FileReader(
				"Resultados\\cora.content1"));

		matrizClasses = new SimpleMatrix(size, classes.length);

		String sCurrentLine;
		while ((sCurrentLine = br.readLine()) != null) {

			String[] cities = sCurrentLine.split("\t");

			int no1 = dicionario2to1.get(Integer.parseInt(cities[0]));

			int no2 = 0;

			for (int i = 0; i < classes.length; i++) {

				if (cities[1].equals(classes[i])) {

					no2 = i;

				}

			}

			matrizClasses.set(no1, no2, 1);

		}
		MatrixIO.print(new PrintStream(new FileOutputStream(
				"Resultados\\matriz_Classes_1.txt")), matrizClasses.getMatrix());

		br.close();

	}

	// Constroi o grafo
	static public void lerArquivo_Nos() throws IOException {

		BufferedReader br = new BufferedReader(new FileReader("cora.cites"));

		ArrayList<Integer> array = new ArrayList<Integer>();

		String sCurrentLine;
		while ((sCurrentLine = br.readLine()) != null) {

			String[] cities = sCurrentLine.split("\t");

			for (int i = 0; i < cities.length; i++) {

				Integer key = Integer.parseInt(cities[i]);
				if (!array.contains(key)) {

					array.add(key);

				}

			}

		}

		br.close();

		Collections.sort(array);

		size = array.size();

		for (int i = 0; i < array.size(); i++) {

			dicionario1to2.put(i, array.get(i));
			dicionario2to1.put(array.get(i), i);

			System.out.println(" " + i + " ==> " + array.get(i));

		}

	}

	public static void main(String[] args) {

		try {

			lerArquivo_Nos();
			criarMatrix_1();
			criarMatriz_2();
			apagarClassesAleatorio();
			relational_Neighbor_Classifier();
			compararResultados();

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	HashMap<Integer, No> heap;

	static String[] classes = { "Case_Based", "Genetic_Algorithms",
			"Neural_Networks", "Probabilistic_Methods",
			"Reinforcement_Learning", "Rule_Learning", "Theory" };

	// 10% das classes devem ser apagadas
	public static void apagarClassesAleatorio() throws FileNotFoundException {

		int NumApagadas = (int) (0.10 * size);

		System.out.println("Numero de classes apagadas: " + NumApagadas);

		Random randomGenerator = new Random();

		classesApagadas = new ArrayList<Integer>(NumApagadas);

		while (classesApagadas.size() < NumApagadas) {

			int i = randomGenerator.nextInt(size);

			if (!classesApagadas.contains(i)) {

				classesApagadas.add(i);

			}

		}

		Collections.sort(classesApagadas);

		System.out.println("Classes apagadas:");
		for (int i = 0; i < classesApagadas.size(); i++) {

			for (int j = 0; j < classes.length; j++) {

				matrizClasses.set(classesApagadas.get(i), j, 0);

			}

			System.out.println(dicionario1to2.get(classesApagadas.get(i)));

		}

		MatrixIO.print(new PrintStream(new FileOutputStream(
				"Resultados\\matriz_Classes_2.txt")), matrizClasses.getMatrix());

	}

	// Metodo em si
	public static void relational_Neighbor_Classifier()
			throws FileNotFoundException {

		SimpleMatrix matrizResultante = matrizNos.mult(matrizClasses);

		for (int i = 0; i < classesApagadas.size(); i++) {

			int classe = -1;
			double n = 0;

			for (int j = 0; j < matrizResultante.numCols(); j++) {

				if (n < matrizResultante.get(classesApagadas.get(i), j)) {

					n = matrizResultante.get(classesApagadas.get(i), j);
					classe = j;

				}

			}

			if (classe != -1) {

				matrizClasses.set(classesApagadas.get(i), classe, 1);

			}

		}

		MatrixIO.print(new PrintStream(new FileOutputStream(
				"Resultados\\matriz_Classes_3.txt")), matrizClasses.getMatrix());

	}
}
